-- lua扩展
local random = math.random

----------------------------------------------------------------------
-- table扩展 
----------------------------------------------------------------------
-- 返回table大小
table.size = function(t)
	local count = 0
	for _,v in pairs(t) do
		count = count + 1
	end
	return count
end

-- 判断table是否为空
table.empty = function(t)
    return not t or not next(t)
end

-- 返回table索引列表
table.indices = function(t)
    local result = {}
    for k, v in pairs(t) do
        table.insert(result, k)
    end
end

-- 返回table值列表
table.values = function(t)
    local result = {}
    for k, v in pairs(t) do
        table.insert(result, v)
    end
end

-- 浅拷贝
table.clone = function(t, nometa)
    local result = {}
    if not nometa then
        setmetatable(result, getmetatable(t))
    end
    for k, v in pairs (t) do
        result[k] = v
    end
    return result
end

-- 深拷贝
table.copy = function(t, nometa)
    local result = {}

    if not nometa then
        setmetatable(result, getmetatable(t))
    end

    for k, v in pairs(t) do
        if type(v) == "table" then
            result[k] = table.copy(v)
        else
            result[k] = v
        end
    end
    return result
end

function table.deepcopy(t, nometa)
    local lookup_table = {}
    local function _copy(t,nometa)
        if type(t) ~= "table" then
            return t
        elseif lookup_table[t] then
            return lookup_table[t]
        end
        local new_table = {}
        lookup_table[t] = new_table
        for index, value in pairs(t) do
            new_table[_copy(index)] = _copy(value)
        end

        if not nometa then
           new_table = setmetatable(new_table, getmetatable(t))
        end
        
        return new_table
    end
    return _copy(t)
end

--合并
table.merge = function(dest, src)
    for k, v in pairs(src) do
        dest[k] = v
    end
end

--连接 
table.concatList = function (tb1,tb2)
    if not tb2 then 
        return 
    end
    for _,v in pairs(tb2) do 
        table.insert(tb1,v)
    end
end
-- 颠倒一个数组类型的table
table.reverse = function (tArray)
    if tArray == nil or #tArray == 0 then
        return {}
    end
    local tArrayReversed = {}
    local nArrCount = #tArray
    for i=1, nArrCount do
        tArrayReversed[i] = tArray[nArrCount-i+1]
    end
    return tArrayReversed
end

--table长度
table.len = function(tb)
    local length = 0
    for _,_ in pairs(tb) do
        length = length + 1
    end
    return length
end

--打乱数组
table.mix = function(arr)
    local sz = #arr
    for i = 1 , sz do
        local r = random(i, sz)
        local t = arr[i]
        arr[i] = arr[r]
        arr[r] = t
    end
end

--取子数组
table.sub = function(arr,star,n)
    local len = #arr
    if not n then 
        n = len
    end
    if len < n or len < star then 
        return {}
    end
    local tb = {}
    for i = star, n do
        table.insert(tb,arr[i])
    end    
    return tb
end

--取剩余的数据(不包含star,star+n)
table.subRest = function(arr,star,n)
    local len = #arr
    if not n then 
        n = len
    end
    local tb = {}
    for i=1, star-1 do
        table.insert(tb,arr[i])
    end
    for i=star+n,len do 
        table.insert(tb,arr[i])    
    end
    return tb
end

table.removeSub = function(tb,tbSub)
    if not tbSub or not next(tbSub) then 
        return
    end
    local tbRemove = {}
    local tb2 = table.copy(tb)
    for k,v in pairs(tb2) do 
        for _,card in pairs(tbSub) do 
            if v == card then 
                table.insert(tbRemove,k)
            end
        end
    end
    local function sort(a,b)
        return a>b
    end 
    table.sort(tbRemove,sort)
    for k,v in pairs(tbRemove) do 
        table.remove(tb2,v)
    end    
    return tb2
end
-----------------

----------------------------------------------------------------------
-- string扩展
----------------------------------------------------------------------

-- 下标运算
do
    local mt = getmetatable("")
    local _index = mt.__index

    mt.__index = function (s, ...)
        local k = ...
        if "number" == type(k) then
            return _index.sub(s, k, k)
        else
            return _index[k]
        end
    end
end

string.split = function(s, delim)
    -- if s == nil or s == '' or delim == nil then
    --     return nil
    -- end

    -- local result = {}
    -- for match in (s..delim):gmatch("(.-)"..delim) do
    --     table.insert(result, match)
    -- end

    -- return result

    local split = {}
    local pattern = "[^" .. delim .. "]+"
    string.gsub(s, pattern, function(v) table.insert(split, v) end)
    return split
end

string.ltrim = function(s, c)
    local pattern = "^" .. (c or "%s") .. "+"
    return (string.gsub(s, pattern, ""))
end

string.rtrim = function(s, c)
    local pattern = (c or "%s") .. "+" .. "$"
    return (string.gsub(s, pattern, ""))
end

string.trim = function(s, c)
    return string.rtrim(string.ltrim(s, c), c)
end

string.isnull = function(s)
    return s == nil
end

string.isempty = function(s)
    return s ~= nil and string.trim(s) == ""
end

string.isnull_or_empty = function(s)
    return s == nil or string.trim(s) == ""
end

function string.subUTF8String(s, n)
    local dropping = string.byte(s, n+1)  
    if not dropping then return s end 
    if dropping >= 128 and dropping < 192 then  
        return string.subUTF8String(s, n-1)  
    end 
    return string.sub(s, 1, n)
end

--去除sql中的特殊字符
function string.SQLStr( str_in, bNoQuotes )
    local str = tostring( str_in )
    str = str:gsub( "'", "''" )
    local null_chr = string.find( str, "\0" )
    if null_chr then
        str = string.sub( str, 1, null_chr - 1 )
    end
    if ( bNoQuotes ) then
        return str
    end
    return "'" .. str .. "'"
end

---不会死循环的dump
local function l_dump(tab, _tostring)
    _tostring = _tostring and _tostring or tostring

    local function getkey(k, ktype)
        if ktype == 'number' then
            return '[' .. k .. ']'
        elseif ktype == 'string' then
            return '["' .. k .. '"]'
        else
            return '[' .. _tostring(k) .. ']'  --key可能是table
        end
    end

    local tinsert = table.insert
    local mmax = math.max
    local rep = string.rep
    local gsub = string.gsub
    local format = string.format

    local function dump_obj(obj, key, sp, lv, st)
        local sp = '\t'

        if type(obj) ~= 'table' then
            return sp .. (key or '') .. ' = ' .. tostring(obj) .. '\n'
        end

        local ks, vs, s= { mxl = 0 }, {}
        lv, st =  lv or 1, st or {}

        st[obj] = key or '.' --table对象列表
        key = key or ''
        for k, v in pairs(obj) do
            local ktype, vtype = type(k), type(v)
            if k ~= 'class' and k ~= '__index' and vtype ~= 'function'then
                if vtype == 'table' then
                    if st[v] then --相互引用的table，直接输出
                        vs[#vs + 1] = '[' .. st[v] .. ']'
                        s = sp:rep(lv) .. getkey(k, ktype)
                        tinsert(ks, s)
                        ks.mxl = mmax(#s, ks.mxl)
                    else
                        st[v] = key .. '.' .. _tostring(k) --保存dump过的table，key可能也是table
                        vs[#vs + 1] = dump_obj(v, st[v], sp, lv + 1, st)
                        s = sp:rep(lv) .. getkey(k, ktype)
                        tinsert(ks, s)
                        ks.mxl = mmax(#s, ks.mxl)
                    end
                else
                    if vtype == 'string' then
                        vs[#vs + 1] = (('%q'):format(v):gsub('\\\10','\\n'):gsub('\\r\\n', '\\n'))
                    else
                        vs[#vs + 1] = tostring(v)
                    end
                    s = sp:rep(lv) .. getkey(k, ktype)
                    tinsert(ks, s)
                    ks.mxl = mmax(#s, ks.mxl);
                end
            end
        end

        s = ks.mxl
        for i, v in ipairs(ks) do
            vs[i] = v .. (' '):rep(s - #v) .. ' = ' .. vs[i] .. '\n'
        end

        return '{\n' .. table.concat(vs) .. sp:rep(lv-1) .. '}'
    end

    return dump_obj(tab)
end

dump = l_dump   --兼容需要
---其他地方需要使用原始的tostring
sys_tostring = tostring
do
    local _tostring = tostring
    tostring = function(v)
        if type(v) == 'table' then
            return l_dump(v, _tostring)
        else
            return _tostring(v)
        end
    end
end


----------------------------------------------------------------------
-- math扩展
----------------------------------------------------------------------
-- 
do
	local _floor = math.floor
	math.floor = function(n, p)
		if p and p ~= 0 then
			local e = 10 ^ p
			return _floor(n * e) / e
		else
			return _floor(n)
		end
	end
end

math.round = function(n, p)
        local e = 10 ^ (p or 0)
        return math.floor(n * e + 0.5) / e
end

--4舍5入
math.four_five = function(n)
    if n % 1 >=0.5 then 
        n = math.ceil(n)
    else
        n = math.floor(n)
    end
    return n
end

--设置随机种子
local _randomseed = math.randomseed
function math.randomseed(num)
    --https://www.cnblogs.com/gggzly/p/5947892.html
    if not num then 
        local time = tostring(os.time())
        math.randomseed(time:reverse():sub(1, 7))
    else
        _randomseed(num)
    end

end


--------------------------------math addon----------------------------------
function math.percentOffset(num,percentage)
    return num + num*(0.5-love.math.random())*2*percentage
end

-- function math.round(num, n)
--     if n > 0 then
--         local scale = math.pow(10, n-1)
--         return math.floor(num * scale + 0.5) / scale
--     elseif n < 0 then
--         local scale = math.pow(10, n)
--         return math.floor(num * scale + 0.5) / scale
--     elseif n == 0 then
--         return num
--     end
-- end
function math.clamp(a,low,high) --取三者中间的
    if low<high then
        return math.max(low,math.min(a,high))
    else
        return math.max(high,math.min(a,low))
    end
end

function math.sign(x)
    if x>0 then return 1
    elseif x<0 then return -1
    else return 0 end
end

function math.polar(x,y) 
  return math.getDistance(x,y,0,0),math.atan2(y, x)
end

function math.cartesian(r,phi)
  return r*math.cos(phi),r*math.sin(phi)
end

function math.getLoopDist(p1,p2,loop)
    loop=loop or 2*Pi
  local dist=math.abs(p1-p2)
    local dist2=loop-math.abs(p1-p2)
  if dist>dist2 then dist=dist2 end
    return dist
end

function math.getDistance(x1,y1,x2,y2)
   return ((x1-x2)^2+(y1-y2)^2)^0.5
end
function math.axisRot(x,y,rot)
    return math.cos(rot)*x-math.sin(rot)*y,math.cos(rot)*y+math.sin(rot)*x
end

function math.axisRot_P(x,y,x1,y1,rot)
  x=x -x1
  y=y- y1
  local xx=math.cos(rot)*x-math.sin(rot)*y
  local yy=math.cos(rot)*y+math.sin(rot)*x
  return xx+x1,yy+y1
end

--取2坐标的弧度
function math.getRot(x1,y1,x2,y2) --p1->p2 direction
    if x1==x2 and y1==y2 then return 0 end 
    local angle = math.atan((x1-x2)/(y1-y2))
    if y1-y2 < 0 then
        angle = angle-math.pi 
    end
    if angle > 0 then
        angle = angle-2*math.pi 
    end
    if angle == 0 then 
        return 0 
    end
    return -angle
end

function math.polygonTrans(x,y,rot,size,v)
    local tab={}
    for i=1,#v/2 do
        tab[2*i-1],tab[2*i]=math.axisRot(v[2*i-1],v[2*i],rot)
        tab[2*i-1]=tab[2*i-1]*size+x
        tab[2*i]=tab[2*i]*size+y
    end
    return tab
end

function math.convexHull(verts)
    local v={}
    local rt={}
    local lastK=0
    local lastX=0
    local lastY=0
    local lastRad=0

    for i=1,#verts-1,2 do
        local index = (i+1)/2
        v[index]={}
        v[index].x=verts[i]
        v[index].y=verts[i+1]
    end
    local maxY=-1/0
    local oK=0
    for k,v in ipairs(v) do
        if v.y>maxY then
            maxY=v.y
            oK=k
        end 
    end
    lastK=oK
    lastX=v[lastK].x
    lastY=v[lastK].y
    table.insert(rt,v[lastK].x)
    table.insert(rt,v[lastK].y)
    local i=0
    while true do
        i=i+1
        local minRad=2*math.pi
        local minK=0
        for k,v in pairs(v) do
            local rad= math.getRot(v.x,v.y,lastX,lastY)
            if rad and rad>lastRad then
                if rad<minRad then
                    minRad=rad
                    minK=k
                end
            end
        end
        if minK==maxK or minK==0 then 
            table.insert(rt,rt[1])
            table.insert(rt,rt[2])
            return rt 
        end --outside
        lastK=minK
        lastRad=minRad
        lastX=v[lastK].x
        lastY=v[lastK].y
        table.insert(rt,v[lastK].x)
        table.insert(rt,v[lastK].y)
    end
end

function math.randomPolygon(x,y,size,count)
    x = x or 0
    y = y or 0
    size = size or 100
    count = count or 30
    local v = {}
    for i=1,count*2 do
        table.insert(v,love.math.random(-50,50)*size/50)
    end
    return math.polygonTrans(x,y,0,1,math.convexHull(v))
end



function math.pointTest(x,y,verts)
    local pX={}
    local pY={}
    for i=1,#verts,2 do
        table.insert(pX, verts[i])
        table.insert(pY, verts[i+1])
    end
    local oddNodes=false
    local pCount=#pX
    local j=pCount
    for i=1,pCount do
        if ((pY[i]<y and pY[j]>=y) or (pY[j]<y and pY[i]>=y))
            and (pX[i]<=x or pX[j]<=x) then
            if pX[i]+(y-pY[i])/(pY[j]-pY[i])*(pX[j]-pX[i])<x then
                oddNodes=not oddNodes
            end
        end
        j=i
    end
    return oddNodes
end

function math.pointTest_xy(x,y,pX,pY)
    local oddNodes=false
    local pCount=#pX
    local j=pCount
    for i=1,pCount do
        if ((pY[i]<y and pY[j]>=y) or (pY[j]<y and pY[i]>=y))
            and (pX[i]<=x or pX[j]<=x) then
            if pX[i]+(y-pY[i])/(pY[j]-pY[i])*(pX[j]-pX[i])<x then
                oddNodes=not oddNodes
            end
        end
        j=i
    end
    return oddNodes
end





function math.RGBtoHSV(r,g,b)
  local max=math.max(r,g,b)
  local min=math.min(r,g,b)
  local d=max-min
  local v=max
  local s
  if v==0 then 
    s=0 
  else 
    s=1-min/max
  end
  local h=0
  if d~=0 then
    if r==max then
      h=(g-b)/d
    elseif g==max then
      h=2+(b-r)/d
    elseif b==max then 
      h=4+(r-g)/d
    end
    h=h*60
    if h<0 then h=h+360 end
  end
  return h,s,v

end

function math.HSVtoRGB(h,s,v)
  local r,g,b
  local x,y,z
  if s==0 then
    r=v;g=v;b=v
  else
    h=h/60
    i=math.floor(h)
    f=h-i
    x=v*(1-s)
    y=v*(1-s*f)
    z=v*(1-s*(1-f))
  end   
  if i==0 then
    r=v;g=z;b=x
  elseif i==1 then
    r=y;g=v;b=x
  elseif i==2 then
    r=x;g=v;b=z
  elseif i==3 then
    r=x;g=y;b=v
  elseif i==4 then
    r=z;g=x;b=v
  elseif i==5 then
    r=v;g=x;b=y
  else
    r=v;g=z;b=x
  end
  return math.floor(r),math.floor(g),math.floor(b)
end


function math.tessellate(vertices,time,factor)
    local new = {}
    local loop = vertices[1] == vertices[#vertices-1] and vertices[2] == vertices[#vertices] 
    factor = factor or .5
    for i=1,#vertices-(loop and 3 or 1),2 do
        local newindex = 2*i
        new[newindex - 1] = vertices[i];
        new[newindex] = vertices[i+1]       
        new[newindex + 1] = (vertices[i] + (vertices[i+2] or vertices[1]))/2
        new[newindex + 2] = (vertices[i+1] + (vertices[i+3] or vertices[2]))/2
    end


    for i = 1,#new -1,4 do     
        new[i] = 
            factor*((new[i - 2] or new[#new-1]) + (new[i + 2] or new[1]))/2 + 
            (1 - factor)*new[i]
        new[i + 1] = 
            factor*((new[i - 1] or new[#new])+ (new[i + 3] or new[2]))/2 + 
            (1 - factor)*new[i + 1]
    end
   
    if loop then
        table.insert(new,new[1])
        table.insert(new,new[2])
    end

    if time == 1 then
        return new
    else 
        return math.tessellate(new,time - 1 ,factor)
    end
end


function math.randomCurve(verts,displace,curDetail)
    local curve = {}
    local random = love.math.random
    local loop = verts[1] == verts[#verts-1] and verts[2] == verts[#verts] 
    for i = 1,#verts-1,2 do
        local segment = {}
        local ox = verts[i]
        local oy = verts[i+1]
        if loop and (not verts[i+2]) then break end
        local nx = verts[i+2] or verts[1]
        local ny = verts[i+3] or verts[2]
        local sample = {{ox,oy,nx,ny,displace,0.5,1}}
        local result = {}   
        while true do
            local newSample = {}            
            for i,seg in ipairs(sample) do                          
                local x1,y1,x2,y2,dp,index,div = unpack(seg)
                div = div + 1
                if dp > curDetail then
                    local mx = (x1 + x2) / 2 + (random() - 0.5) * displace
                    local my = (y1 + y2) / 2 + (random() - 0.5) * displace
                    table.insert(newSample,{x1,y1,mx,my,dp/2,index-1/(2^div),div})
                    table.insert(newSample,{mx,my,x2,y2,dp/2,index+1/(2^div),div})
                else
                    table.insert(result,seg)
                end
            end
            if not newSample[1] then break end
            sample = newSample

        end
        table.sort(result,function(a,b) return a[6]<b[6] end)
        for i,v in ipairs(result) do
            table.insert(curve, v[1])
            table.insert(curve, v[2])
            --table.insert(curve, v[3])
            --table.insert(curve, v[4])
        end
        
    end
    table.insert(curve,curve[1])
    table.insert(curve,curve[2])
    return curve
end


function math.pointToLine(a,b,c,x,y)
  return math.abs(a*x+b*y+c)/math.sqrt(a*a+b*b)
end


--source 必须包含.x,.y作为起始坐标，.rot为发射角,tx,ty为终点坐标
--toTest为待检测table 必须包含 .x,.y,.r作为碰撞球
function math.raycast(source,toTest) 
  local x1,y1=source.x,source.y
  local x2,y2
  local dist
  local dir=source.rot or math.atan((source.tx-x1)/(source.ty-y1))-math.pi/2
  local tan=math.tan(dir) 
  local a=tan
  local b=-1
  local c=-x1*tan+y1
  local rt={}
  for i,v in ipairs(toTest) do
      x2,y2=v.x,v.y
      dist=math.pointToLine(a,b,c,x2,y2)
      if math.sign(math.cos(dir))~=math.sign(x2-x1) and math.sign(math.sin(dir))~=math.sign(y2-y1) then
        dist=math.tan(Pi/2)
      end
      if dist<= v.r then
        local a2,b2,c2=math.vertToLine(a,b,c,x2,y2)
        local cx,cy=math.crossPoint(a,b,c,a2,b2,c2)
        
        if source.tx then
            if math.abs(cx - math.clamp(cx,source.x,source.tx))<2
             and math.abs(cy - math.clamp(cy,source.y,source.ty))<2 then
                table.insert(rt, {v,cx,cy})
            end
        else
            if cx == math.clamp(cx,source.x,(1/0)*math.sin(dir)) and cy == math.clamp(cy,source.y,(1/0)*math.cos(dir)) then
                table.insert(rt, {v,cx,cy})
            end
        end
        
      end
  end
  return rt
end

function math.getLineABC(x,y,tx,ty)
    local a = (ty-y)/(tx-x)
    local b = -1
    local c = -x*a+y
    return a,b,c
end

function math.lineCross(line1,line2)
    local a1,b1,c1 = math.getLineABC(line1.x,line1.y,line1.tx,line1.ty)
    local a2,b2,c2 = math.getLineABC(line2.x,line2.y,line2.tx,line2.ty)
    local cx,cy=math.crossPoint(a1,b1,c1,a2,b2,c2)
    if  math.abs(cx - math.clamp(cx,line1.x,line1.tx))<2
     and math.abs(cy - math.clamp(cy,line1.y,line1.ty))<2
     and math.abs(cx - math.clamp(cx,line2.x,line2.tx))<2
     and math.abs(cy - math.clamp(cy,line2.y,line2.ty))<2 then
        return cx,cy
    end
end


function math.unitAngle(angle)  --convert angle to 0,2*Pi
    return math.asin(math.sin(angle))
end

function math.vertToLine(a,b,c,x,y) --过已知点垂线公式
  local a2=math.abs(b/a)==1/0 and math.sign(b/a)*math.tan(Pi/2) or b/a
  return a2,-1,y-a2*x
end


function math.crossPoint(a1,b1,c1,a2,b2,c2) --两线交点公式
  return (b1*c2-b2*c1)/(a1*b2-a2*b1), (a1*c2-a2*c1)/(b1*a2-b2*a1)
end

function math.createEllipse(rx,ry,segments)
    segments = segments or 30
    local vertices = {}
    for i=0, segments do
        local angle = (i / segments) * math.pi * 2
        local x = math.cos(angle)*rx
        local y = math.sin(angle)*ry
        table.insert(vertices, x)
        table.insert(vertices, y)
    end
    
    return vertices
end

--return center,area verts[1],verts[2] = x ,y
function math.getPolygonArea(verts) 
    local count=#verts/2
    local cx,cy=0,0
    local area = 0
    local inv3=1/3
    local refx,refy=0,0
    for i=1,#verts-1,2 do
        local p1x,p1y=refx,refy
        local p2x,p2y=verts[i],verts[i+1]
        local p3x = i+2>#verts and verts[1] or verts[i+2]
        local p3y = i+2>#verts and verts[2] or verts[i+3]

        local e1x= p2x-p1x
        local e1y= p2y-p1y
        local e2x= p3x-p1x
        local e2y= p3y-p1y

        local d=math.vec2.cross(e1x,e1y,e2x,e2y)
        local triAngleArea=0.5*d
        area=area+triAngleArea
        cx = cx + triAngleArea*(p1x+p2x+p3x)/3
        cy = cy + triAngleArea*(p1y+p2y+p3y)/3
    end

    if area~=0 then
        cx= cx/area
        cy= cy/area
        return cx,cy,math.abs(area)
    end
end


----------------------------------------------------------------------
-- lua面向对象扩展
----------------------------------------------------------------------
-- 
function class(classname, super)
	local superType = type(super)
	local cls
	if superType ~= 'function' and superType ~= 'table' then
		superType = nil
		super = nil
	end

	if superType == 'function' or (super and super.__ctype == 1) then
		-- inherited from native C++ Object
		cls = {}
		if superType == 'table' then
			-- copy fields from super
			for k,v in pairs(super) do cls[k] = v end
			cls.__create = super.__create
			cls.super = super
		else
			cls.__create = super
			cls.ctor = function() end
		end
		cls.__cname = classname
		cls.__ctype = 1

		function cls.new(...)
			local instance = cls.__create(...)
			-- copy fields from class to  native object
			for k, v in pairs(cls) do instance[k] = v end
			instance.class = cls
			instance:ctor(...)
			return instance
		end
                cls.New = cls.new
	else
		-- inherited from Lua Object
		if super then
			cls = {}
			setmetatable(cls, {__index = super})
			cls.super = super
		else
			cls = {ctor = function() end}
		end
		cls.__cname = classname
		cls.__ctype = 2 --lua
		cls.__index = cls
        function cls.getName()
            return cls.__cname
        end
		function cls.new(...)
			local instance = setmetatable({}, cls)
			instance.class = cls
			instance:ctor(...)
			return instance
		end
        cls.New = cls.new
	end
	return cls
end

function handler(obj, method)
    return function(...)
        return method(obj, ...)
    end
end

function isclass(o, cname)
    if (not o) or (not cname) then return false end

    local ic = o and (o.__cname == cname)
    if (not ic) and (o and o.super) then
        return isclass(o.super, cname)
    else
        return ic
    end
end

function clone(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for key, value in pairs(object) do
            new_table[_copy(key)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

function tonumber_d(v, default)
    default = default or 0
    return tonumber(v) or default
end

function tostring_d(v, default)
    default = default or ""
    return (v == nil) and default or tostring(v)
end
----------------------------------------------------------------------
-- 
----------------------------------------------------------------------